package com.generator.common.util;

import com.generator.common.bean.DatabaseBean;
import com.generator.common.bean.TableColumnBean;
import com.generator.common.constant.BaseConstant;
import com.generator.common.dao.MbgDbInfoMapper;
import com.generator.common.dao.SqlLiteMapper;
import com.generator.common.enums.DbType;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.log4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.generator.common.constant.BaseConstant.SQLLITE_DB_ID;

/**
 * @author syl
 * @create 2018-03-23 17:50
 **/
public class DbConnectionUtil {
    private static final Logger LOG = Logger.getLogger(DbConnectionUtil.class);
    public static Map<String,PooledDataSource> connectionCache = new HashMap<>();
    public static Map<String,SqlSessionFactory>     sessionFactoryCache = new HashMap<>();

    public static boolean testConnection(DatabaseBean bean,String dbID){
        PooledDataSource ds = getDataSource(bean,true,dbID);
        if(ds == null) {
            return false;
        }
        String key = bean.getConnectionURL()+dbID;
        if(!connectionCache.containsKey(key)) {
            connectionCache.put(key,ds);
        }
        return true;
    }

    private static PooledDataSource getDataSource(DatabaseBean bean,boolean test,String dbID){
        if(connectionCache.containsKey(dbID))return  connectionCache.get(dbID);
        PooledDataSource pds = new PooledDataSource();
        try {
            pds.setDriver(bean.getDriverClass());
            pds.setUrl(bean.getConnectionURL());
            pds.setUsername(bean.getUsername());
            pds.setPassword(bean.getPassword());
            pds.setPoolMaximumIdleConnections(0);
            pds.setPoolMaximumActiveConnections(300);
            pds.setPoolPingEnabled(true);
            pds.setPoolPingConnectionsNotUsedFor(10000);
            pds.setPoolPingQuery("select 1");
            Connection connection = pds.getConnection();//测试连接
            LOG.info(bean.getDbType()+"连接成功："+dbID);
            connection.close();
            if(!connectionCache.containsKey(dbID)) {
                connectionCache.put(dbID,pds);
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage());
            LOG.info(bean.getDbType()+"连接失败了 请检查参数是否正确");
            return null;
        }
        return pds;
    }

    /**
     * 获取mybatis session
     * @param bean
     * @param dbID
     * @return
     */
    public static SqlSession getAutoSession(DatabaseBean bean,String dbID){
        SqlSessionFactory factory = getSqlSessionFactory(bean, dbID);
        if(factory == null) {
            throw new RuntimeException("连接不上数据库");
        }
        return factory.openSession(true);
    }

    public static SqlSessionFactory getSqlSessionFactory(DatabaseBean bean,String dbID){
        String key = bean.getConnectionURL()+dbID;
        if(sessionFactoryCache.containsKey(key)) {
            return sessionFactoryCache.get(key);
        }
        PooledDataSource dataSource = connectionCache.get(key);
        if(dataSource == null){
           dataSource = getDataSource(bean,true,dbID);
        }
        Configuration config = new Configuration();
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment(dbID, transactionFactory, dataSource);
        config.setEnvironment(environment);

        config.getMapperRegistry().addMapper(SqlLiteMapper.class);
        config.getMapperRegistry().addMapper(MbgDbInfoMapper.class);
        LOG.info("Mapper Registry: "+config.getMapperRegistry().getMappers());
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(config);
        if(sessionFactory != null)sessionFactoryCache.put(key,sessionFactory);
        LOG.info("创建了  sessionFactory "+dbID);
        return sessionFactory;
    }

    /**
     * 获取数据库表或列信息
     * @param bean
     * @param type 查询类型 0:查询所有表 1:查询所有列
     * @return
     */
    public static List<TableColumnBean> getTableColumnList(DatabaseBean bean,int type){
        SqlSession session = DbConnectionUtil.getAutoSession(bean, bean.getName());
        String daoName = DbType.valueOf(bean.getDbType()).getDaoName();
        MbgDbInfoMapper mapper = session.getMapper(MbgDbInfoMapper.class);
        List<TableColumnBean> columnList = null;
        try {
            Method method = null;
            if(type == 0) {
                method = mapper.getClass().getMethod(BaseConstant.TABLE_METHOD_NAME.replace("XXX", daoName), String.class);
                columnList = (List<TableColumnBean>) method.invoke(mapper, bean.getSchema());
            }else if(type == 1) {
                method = mapper.getClass().getMethod(BaseConstant.COLUMN_METHOD_NAME.replace("XXX",daoName),String.class,String.class);
                columnList = (List<TableColumnBean>) method.invoke(mapper,bean.getSchema(),bean.getTableName());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return columnList;
    }

    public static SqlLiteMapper getSqliteDao(){
        DatabaseBean bean = new DatabaseBean(DbType.SqlLite,"",0,  "", "", "", "");
        PooledDataSource dataSourc = getDataSource(bean, false,BaseConstant.SQLLITE_DB_ID);
        LOG.info(dataSourc.getPoolState().getActiveConnectionCount()+"  正在使用连接数");
        LOG.info(dataSourc.getPoolState().getIdleConnectionCount()+"  闲置连接数");
        SqlSession session1 = getAutoSession(bean,SQLLITE_DB_ID);

        return session1.getMapper(SqlLiteMapper.class);
    }



//    public db void closeSqliteSession(){
//        DatabaseBean bean = new DatabaseBean(DbType.SqlLite,"",0,  "", "", "", "");
//        SqlSession session1 = getAutoSession(bean,SQLLITE_DB_ID);
//        session1.close();
//    }
}
